#include "pch.h"
#include "GRTXTriangle.h"

bool GRTXTriangle::IsLight() const
{
	return Emission.Length() > GGiEngineUtil::EPSILION;
}

void GRTXTriangle::SampleLight(GRiVertex& samplePos, float& pdf) const
{
	float u, v;
	do 
	{
		u = GGiEngineUtil::GetRandom();
		v = GGiEngineUtil::GetRandom();
	} while (u + v >1);

	samplePos = Interpolation(u, v);
	pdf = 1.0f / Area;
}

HitInfo GRTXTriangle::Interset(const GRTXRay& ray)const
{
	HitInfo info;

	float t, u, v;
	if (IsInside(ray,t,u,v))
	{
		if (IsLight())
		{
			info.isLight = true;
			info.emission = Emission;
		}

		info.isHit = true;
		info.mat = *pMat;
		info.p = Interpolation(u, v);
		info.t = t;
	}
	return info;
}

bool GRTXTriangle::IsInside(const GRTXRay& ray, float& t, float& u, float& v) const
{
	const auto& dir = ray.Dir;

	const auto e1_x_d = E1.Cross(dir);
	const float denominator = e1_x_d.Dot(E2);

	if (denominator == 0)
		return false;

	const float inv_denominator = 1.0f / denominator;

	const auto s = ray.Orgin - V0.Position;

	const auto e2_x_s = E2.Cross(s);
	const float r1 = e2_x_s.Dot(dir);
	u = r1 * inv_denominator;
	if (u < 0 || u > 1) {
		return false;
	}

	const float r2 = e1_x_d.Dot(s);
	v = r2 * inv_denominator;
	if (v < 0 || v > 1) {
		return false;
	}

	const float u_plus_v = u + v;
	if (u_plus_v > 1) {
		return false;
	}

	const float r3 = e2_x_s.Dot(E1);
	t = r3 * inv_denominator;

	if (t < 0)
	{
		return false;
	}
	return true;
}

GRiVertex GRTXTriangle::Interpolation(float u, float v) const
{
	GRiVertex ans;
	ans.Position = V0.Position * (1 - u - v) + V1.Position * u + V2.Position * v;
	ans.TangentU = V0.TangentU * (1 - u - v) + V1.TangentU * u + V2.TangentU * v;
	ans.Normal = V0.Normal * (1 - u - v) + V1.Normal * u + V2.Normal * v;
	ans.UV = V0.UV * (1 - u - v) + V1.UV * u + V2.UV * v;

	ans.Normal = ans.Normal.Normalize();

	return ans;
}

